use std::fs::File;
use std::io::Read;
use captcha::Captcha;
use captcha::filters::Noise;
use crypto::digest::Digest;
use crypto::sha3::Sha3;
use jsonwebtoken::{decode, encode, errors::Result, EncodingKey, Header, TokenData, DecodingKey, Validation};
use md5::compute;
use crate::domain::{ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY};
use crate::domain::dto::login_dto::{UserRefreshTokenClaims, UserTokenClaims};
use crate::domain::entity::user_entity::UserEntity;

/// page_tools 分页工具
pub fn page_tools(page:u64, limit:u64) -> (u64, u64) {
    let mut size = 10;
    if page > 1 {
        size = limit
    }
    let mut num = 0;
    if page > 1 {
        num = (page - 1) * size
    }
    (num, size)
}

/// create_captcha 创建验证码
pub fn create_captcha() -> (String, Option<String>) {
    let mut captcha_obj = Captcha::new();
    captcha_obj.add_chars(5)
        .apply_filter(Noise::new(0.1))
        .view(200, 80);
    (captcha_obj.chars_as_string(), captcha_obj.as_base64())
}

/// build_md5 创建 md5
#[allow(dead_code)]
pub fn build_md5(password: String, salt: &str) -> String{
    let target = format!("{}-{}", password, salt);
    let digest = compute(target);
    format!("{:x}",digest)
}

#[allow(dead_code)]
pub fn build_sh265(password: &str, salt: &str) -> String {
    let mut hasher = Sha3::sha3_256();
    hasher.input_str(format!("{}{}", salt, password).as_str());
    hasher.result_str()
}

/// create_access_token 创建认证token
#[allow(dead_code)]
pub fn create_access_token(user: UserEntity, expire_time: i64) -> Result<String> {
    let claims = UserTokenClaims::new(user, expire_time);
    encode(&Header::default(),
           &claims,
           &EncodingKey::from_secret(ACCESS_TOKEN_KEY.as_ref()))
}

/// create_refresh_token 创建刷新token
#[allow(dead_code)]
pub fn create_refresh_token(user_id: u64, expire_time: i64) -> Result<String> {
    let claims = UserRefreshTokenClaims::new(user_id, expire_time);
    encode(&Header::default(),
           &claims,
           &EncodingKey::from_secret(REFRESH_TOKEN_KEY.as_ref()))
}

/// verify_token 验证token
#[allow(dead_code)]
pub fn verify_token(token: &str) -> Result<TokenData<UserTokenClaims>> {
    decode::<UserTokenClaims>(token,
                              &DecodingKey::from_secret(ACCESS_TOKEN_KEY.as_ref()),
                              &Validation::default())
}

/// read_json 读取json文件
#[allow(dead_code)]
pub fn read_json(path: &str) -> std::io::Result<String> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}
